/*
 * (C) 2014-2015 Alibaba Group Holding Limited
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *
 *     __  ___   ______        ___       __          ___
 *    |  |/  /  /  __  \      /   \     |  |        /   \
 *    |  '  /  |  |  |  |    /  ^  \    |  |       /  ^  \
 *    |    <   |  |  |  |   /  /_\  \   |  |      /  /_\  \
 *    |  .  \  |  `--'  |  /  _____  \  |  `----./  _____  \
 *    |__|\__\  \______/  /__/     \__\ |_______/__/     \__\
 *
 *
 *
 */
//
// Created by KOALA TEAM on 12/19/14.
//

#import "NSString+KLHelper.h"
#import <CommonCrypto/CommonDigest.h>
#import "KLFirstLetter.h"
#import "NSObject+KLTypeConversion.h"

int const GGCharacterIsNotADigit = 10;

@implementation NSString (KLHelper)

+ (NSString*)stringWithFormattedUnsignedInteger:(NSUInteger)integer {
    NSNumber* number = [NSNumber numberWithUnsignedInteger:integer];
    NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
	NSString* formattedString = [formatter stringFromNumber:number];
	return formattedString;
}

- (NSString *)trim {
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

- (BOOL)containsString:(NSString*)string {
	return [self containsString:string options:NSCaseInsensitiveSearch];
}

- (BOOL)containsString:(NSString*)string options:(NSStringCompareOptions)options {
	return [self rangeOfString:string options:options].location == NSNotFound ? NO : YES;
}

- (BOOL) containsEngAlphabet {
    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@".*[a-zA-Z]+.*" options:NSRegularExpressionAllowCommentsAndWhitespace error:&error];
    
    return [regex firstMatchInString:self options:NSMatchingAnchored range:NSRangeFromString(self)] != nil;
}

#pragma mark -
#pragma mark Long conversions

- (long)longValue {
	return (long)[self longLongValue];
}

- (long long)longLongValue {
	NSScanner* scanner = [NSScanner scannerWithString:self];
	long long valueToGet;
	if ([scanner scanLongLong:&valueToGet] == YES) {
		return valueToGet;
	}

    return 0;
}

- (unsigned)digitValue:(unichar)c {
	if ((c > 47) && (c < 58)) {
        return (c - 48);
	}

	return GGCharacterIsNotADigit;
}

- (unsigned long long)unsignedLongLongValue {
	unsigned n = [self length];
	unsigned long long v,a;
	unsigned small_a, j;

	v = 0;
	for (j=0; j<n; j++) {
		unichar c = [self characterAtIndex:j];
		small_a = [self digitValue:c];
		if (small_a == GGCharacterIsNotADigit) continue;
		a = (unsigned long long)small_a;
		v = (10 * v) + a;
	}

	return v;
}

- (BOOL)isNotBlank {
    return [KLRONSStringUtil isNotBlank:self];
}

- (BOOL)isEmpty{
    return ![KLRONSStringUtil isNotBlank:self];
}

- (NSString *)md5 {
	const char *str = [self UTF8String];
	unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, strlen(str), result);

	NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
	for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
		[ret appendFormat:@"%02x", result[i]];
	}
	return ret;
}

- (NSString *)SHA1 {
    const char *cstr = [self UTF8String];
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, data.length, digest);
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }

    return output;
}

#pragma mark -
#pragma mark Truncation

- (NSString*)stringByTruncatingToLength:(int)length {
	return [self stringByTruncatingToLength:length direction:NSTruncateStringPositionEnd];
}

- (NSString*)stringByTruncatingToLength:(int)length direction:(NSTruncateStringPosition)truncateFrom {
	return [self stringByTruncatingToLength:length direction:truncateFrom withEllipsisString:@"..."];
}

- (NSString*)stringByTruncatingToLength:(int)length
                              direction:(NSTruncateStringPosition)truncateFrom
                     withEllipsisString:(NSString*)ellipsis {
	NSMutableString *result = [[NSMutableString alloc] initWithString:self];
	NSString *immutableResult;

	if ([result length] <= length) {
//		[result release];
		return self;
	}

	unsigned int charactersEachSide = length / 2;

	NSString* first;
	NSString* last;

	switch(truncateFrom) {
		case NSTruncateStringPositionStart:
			[result insertString:ellipsis atIndex:[result length] - length + [ellipsis length] ];
			immutableResult  = [[result substringFromIndex:[result length] - length] copy];
//			[result release];
//			return [immutableResult autorelease];
            return immutableResult;
		case NSTruncateStringPositionMiddle:
			first = [result substringToIndex:charactersEachSide - [ellipsis length]+1];
			last = [result substringFromIndex:[result length] - charactersEachSide];
			immutableResult = [[[NSArray arrayWithObjects:first, last, NULL] componentsJoinedByString:ellipsis] copy];
//			[result release];
//			return [immutableResult autorelease];
            return immutableResult;
		default:
		case NSTruncateStringPositionEnd:
			[result insertString:ellipsis atIndex:length - [ellipsis length]];
			immutableResult  = [[result substringToIndex:length] copy];
//			[result release];
//			return [immutableResult autorelease];
            return immutableResult;
	}
}


- (NSString *)URLEncodedString {
    NSString *result = ( NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                    ( CFStringRef)self, NULL,
                                                                                    CFSTR("!*'();:@&=+$,/?%#[]"),
                                                                                    kCFStringEncodingUTF8));
//    [result autorelease];
    return result;
}

- (NSString *)stripStrangeWords {
    /* 当输入中文时未完成，直接提交，需要过滤这个奇怪的字符 */
    static char _mark[4] = { 0xe2, 0x80, 0x86, '\0' };
    NSString *divstr = [NSString stringWithUTF8String:(const char *)_mark];
    return [self stringByReplacingOccurrencesOfString:divstr withString:@""];
}

- (int)lengthOfBytesUsingGB18030Encoding{
    NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    return (int) ceill([self lengthOfBytesUsingEncoding:enc] / 2.f);
}



- (NSString *)substringFromIndex:(NSUInteger)from untilCharset:(NSCharacterSet *)charset endOffset:(NSUInteger *)endOffset
{
    if ( 0 == self.length )
        return nil;
    
    if ( from >= self.length )
        return nil;
    
    NSRange range = NSMakeRange( from, self.length - from );
    NSRange range2 = [self rangeOfCharacterFromSet:charset options:NSCaseInsensitiveSearch range:range];
    
    if ( NSNotFound == range2.location )
    {
        if ( endOffset )
        {
            *endOffset = range.location + range.length;
        }
        
        return [self substringWithRange:range];
    }
    else
    {
        if ( endOffset )
        {
            *endOffset = range2.location + range2.length;
        }
        
        return [self substringWithRange:NSMakeRange(from, range2.location - from)];
    }
}


- (NSArray *)words
{
#if ! __has_feature(objc_arc)
    NSMutableArray *words = [[[NSMutableArray alloc] init] autorelease];
#else
    NSMutableArray *words = [[NSMutableArray alloc] init];
#endif
    
    const char *str = [self cStringUsingEncoding:NSUTF8StringEncoding];
    
    char *word;
    for (int i = 0; i < strlen(str);) {
        int len = 0;
        if (str[i] >= 0xFFFFFFFC) {
            len = 6;
        } else if (str[i] >= 0xFFFFFFF8) {
            len = 5;
        } else if (str[i] >= 0xFFFFFFF0) {
            len = 4;
        } else if (str[i] >= 0xFFFFFFE0) {
            len = 3;
        } else if (str[i] >= 0xFFFFFFC0) {
            len = 2;
        } else if (str[i] >= 0x00) {
            len = 1;
        }
        
        word = malloc(sizeof(char) * (len + 1));
        for (int j = 0; j < len; j++) {
            word[j] = str[j + i];
        }
        word[len] = '\0';
        i = i + len;
        
        NSString *oneWord = [NSString stringWithCString:word encoding:NSUTF8StringEncoding];
        free(word);
        [words addObject:oneWord];
    }
    
    return words;
}


- (NSString *)urldecode {
    return [self stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}

////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString *)urlencode {
    NSString *encUrl = [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSUInteger len = [encUrl length];
    const char *c;
    c = [encUrl UTF8String];
    NSString *ret = @"";
    for(int i = 0; i < len; i++) {
        switch (*c) {
            case '~':
                ret = [ret stringByAppendingString:@"%7E"];
                break;
            case '/':
                ret = [ret stringByAppendingString:@"%2F"];
                break;
            case '\'':
                ret = [ret stringByAppendingString:@"%27"];
                break;
            case ';':
                ret = [ret stringByAppendingString:@"%3B"];
                break;
            case '?':
                ret = [ret stringByAppendingString:@"%3F"];
                break;
            case ':':
                ret = [ret stringByAppendingString:@"%3A"];
                break;
            case '@':
                ret = [ret stringByAppendingString:@"%40"];
                break;
            case '&':
                ret = [ret stringByAppendingString:@"%26"];
                break;
            case '=':
                ret = [ret stringByAppendingString:@"%3D"];
                break;
            case '+':
                ret = [ret stringByAppendingString:@"%2B"];
                break;
            case '$':
                ret = [ret stringByAppendingString:@"%24"];
                break;
            case ',':
                ret = [ret stringByAppendingString:@"%2C"];
                break;
            case '[':
                ret = [ret stringByAppendingString:@"%5B"];
                break;
            case ']':
                ret = [ret stringByAppendingString:@"%5D"];
                break;
            case '#':
                ret = [ret stringByAppendingString:@"%23"];
                break;
            case '!':
                ret = [ret stringByAppendingString:@"%21"];
                break;
            case '(':
                ret = [ret stringByAppendingString:@"%28"];
                break;
            case ')':
                ret = [ret stringByAppendingString:@"%29"];
                break;
            case '*':
                ret = [ret stringByAppendingString:@"%2A"];
                break;
            default:
                ret = [ret stringByAppendingFormat:@"%c", *c];
        }
        c++;
    }
    
    return ret;
}

- (NSString *)urlByAppendingDict:(NSDictionary *)params encoding:(BOOL)encoding
{
    NSURL * parsedURL = [NSURL URLWithString:self];
    NSString * queryPrefix = parsedURL.query ? @"&" : @"?";
    NSString * query = [NSString queryStringFromDictionary:params encoding:encoding];
    return [NSString stringWithFormat:@"%@%@%@", self, queryPrefix, query];
}

+ (NSString *)queryStringFromDictionary:(NSDictionary *)dict encoding:(BOOL)encoding
{
    NSMutableArray * pairs = [NSMutableArray array];
    for ( NSString * key in dict.allKeys )
    {
        NSString * value = [(NSObject *)[dict objectForKey:key] asNSString];
        NSString * urlEncoding = encoding ? [value urlencode] : value;
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, urlEncoding]];
    }
    return [pairs componentsJoinedByString:@"&"];
}

-(NSString *)getOutOfTheNumber{
    NSMutableString *strippedString = [NSMutableString
                                       stringWithCapacity:self.length];
    
    NSScanner *scanner = [NSScanner scannerWithString:self];
    NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
    while ([scanner isAtEnd] == NO) {
        NSString *buffer;
        if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
            [strippedString appendString:buffer];
        }
        else {
            [scanner setScanLocation:([scanner scanLocation] + 1)];
        }
    }
    return strippedString;
}



- (NSString *)firstLetter
{
    return [KLFirstLetter firstLetter:self];
}

- (NSString *)firstLetters
{
    return [KLFirstLetter firstLetters:self];
}



// 十六进制转换为普通字符串的。
- (NSData *)toHexData {
    NSString *hexString = self;
    NSData *data = nil;
    char *myBuffer = (char *) malloc((int) [hexString length] / 2 + 1);
    if (myBuffer) {
        bzero(myBuffer, [hexString length] / 2 + 1);
        for (int i = 0; i < [hexString length] - 1; i += 2) {
            unsigned int anInt;
            NSString *hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)];
            NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
            [scanner scanHexInt:&anInt];
            myBuffer[i / 2] = (char) anInt;
        }

        data = [NSData dataWithBytes:myBuffer length:[hexString length] / 2];
        NSString *unicodeString = [NSString stringWithCString:myBuffer encoding:NSUTF8StringEncoding];
        free(myBuffer);
        myBuffer = nil;
    }
    return data;
}

//普通字符串转换为十六进制的。
+ (NSString *)stringFromData:(NSData *)data{
    NSData *myD = data;//[string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++){
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr]; 
    } 
    return hexStr; 
}



+(NSString *)jsonStringWithString:(NSString *) string{
    return [NSString stringWithFormat:@"\"%@\"",
            [[string stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"] stringByReplacingOccurrencesOfString:@"\""withString:@"\\\""]
            ];
}
+(NSString *)jsonStringWithArray:(NSArray *)array{
    NSMutableString *reString = [NSMutableString string];
    [reString appendString:@"["];
    NSMutableArray *values = [NSMutableArray array];
    for (id valueObj in array) {
        NSString *value = [NSString jsonStringWithObject:valueObj];
        if (value) {
            [values addObject:[NSString stringWithFormat:@"%@",value]];
        }
    }
    [reString appendFormat:@"%@",[values componentsJoinedByString:@","]];
    [reString appendString:@"]"];
    return reString;
}
+(NSString *)jsonStringWithDictionary:(NSDictionary *)dictionary{
    NSArray *keys = [dictionary allKeys];
    NSMutableString *reString = [NSMutableString string];
    [reString appendString:@"{"];
    NSMutableArray *keyValues = [NSMutableArray array];
    for (int i=0; i<[keys count]; i++) {
        NSString *name = [keys objectAtIndex:i];
        id valueObj = [dictionary objectForKey:name];
        NSString *value = [NSString jsonStringWithObject:valueObj];
        if (value) {
            [keyValues addObject:[NSString stringWithFormat:@"\"%@\":%@",name,value]];
        }
    }
    [reString appendFormat:@"%@",[keyValues componentsJoinedByString:@","]];
    [reString appendString:@"}"];
    return reString;
}
+(NSString *)jsonStringWithObject:(id) object{
    NSString *value = nil;
    if (!object) {
        return value;
    }
    if ([object isKindOfClass:[NSString class]]) {
        value = [NSString jsonStringWithString:object];
    }else if([object isKindOfClass:[NSDictionary class]]){
        value = [NSString jsonStringWithDictionary:object];
    }else if([object isKindOfClass:[NSArray class]]){
        value = [NSString jsonStringWithArray:object];
    }
    return value;
}


+(NSString *)stringFromResFile:(NSString *)name encoding:(NSStringEncoding)encode{
    return [NSString stringWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:name] encoding:encode error:nil];
}
@end

@implementation KLRONSStringUtil {
    
}

+ (BOOL)isWhiteSpace:(unichar)ch {
    return [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:ch];
}

+ (BOOL)isBlank:(NSString *)str {
    NSUInteger strLen;
    if (str == nil || (strLen = str.length) == 0) {
        return YES;
    }
    for (NSUInteger i = 0; i < strLen; i++) {
        if (![self isWhiteSpace:[str characterAtIndex:i]]) {
            return NO;
        }
    }
    
    return YES;
}

+ (BOOL)isNotBlank:(NSString *)str {
    return ![self isBlank:str];
}


+ (NSString *)safeConvertString:(NSString *)value {
    return value == nil ? @"" : value;
}


@end

